/**
 * 数据库初始化服务
 * 作者：GodMainCode
 * 创建时间：2024-01-17
 * 修改时间：2024-01-17
 * 修改人：GodMainCode
 */

import { Injectable, OnModuleInit, Logger } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { InjectDataSource } from '@nestjs/typeorm';
import { ConfigService } from '@nestjs/config';
import * as fs from 'fs';
import * as path from 'path';

@Injectable()
export class DatabaseInitService implements OnModuleInit {
  private readonly logger = new Logger(DatabaseInitService.name);

  constructor(
    @InjectDataSource()
    private dataSource: DataSource,
    private configService: ConfigService,
  ) {}

  async onModuleInit() {
    await this.initializeTables();
  }

  private async initializeTables() {
    try {
      const dbType = this.configService.get<string>('DB_TYPE');
      
      // 获取SQL文件路径
      const sqlPath = this.getSqlFilePath();
      const initSql = dbType === 'postgres' 
        ? await this.readSqlFile(path.join(sqlPath, 'postgres-init.sql'))
        : await this.readSqlFile(path.join(sqlPath, 'mysql-init.sql'));

      // 执行SQL语句
      if (dbType === 'postgres') {
        // 分割SQL语句
        const statements = initSql.split(/;\s*$/m).filter(stmt => stmt.trim());
        
        // 按顺序执行SQL语句
        for (const statement of statements) {
          if (statement.trim()) {
            try {
              // 跳过注释
              if (!statement.trim().startsWith('--')) {
                await this.dataSource.query(statement);
                // 如果是创建表的语句，输出日志
                if (statement.toLowerCase().includes('create table')) {
                  const tableName = statement.match(/create table.*?"(\w+)"/i)?.[1];
                  if (tableName) {
                    this.logger.log(`创建表: ${tableName}`);
                  }
                }
              }
            } catch (error) {
              this.logger.error(`执行SQL语句失败: ${statement}`);
              this.logger.error(`错误信息: ${error.message}`);
              throw error;
            }
          }
        }

        // 执行表和字段注释
        try {
          const commentsSql = await this.readSqlFile(path.join(sqlPath, 'postgres-comments.sql'));
          const commentStatements = commentsSql.split(/;\s*$/m).filter(stmt => stmt.trim());
          
          for (const statement of commentStatements) {
            if (statement.trim() && !statement.trim().startsWith('--')) {
              try {
                await this.dataSource.query(statement);
                if (statement.toLowerCase().includes('comment on table')) {
                  const tableName = statement.match(/comment on table\s+"?(\w+)"?\s+is/i)?.[1];
                }
              } catch (error) {
                // 注释添加失败不影响主流程
                this.logger.warn(`添加注释失败: ${error.message}`);
              }
            }
          }
          this.logger.log('数据库表注释添加完成');
        } catch (error) {
          this.logger.warn('添加数据库注释失败，但不影响主流程:', error.message);
        }
      } else {
        // MySQL的处理逻辑
        const createTableStatements = initSql
          .split(/(?<=;)\s*(?=CREATE)/i)
          .filter(stmt => stmt.trim());

        // 先创建所有表
        for (const statement of createTableStatements) {
          if (statement.trim() && statement.toUpperCase().includes('CREATE TABLE')) {
            try {
              await this.dataSource.query(statement);
              const tableName = statement.match(/CREATE TABLE.*?`(\w+)`/i)?.[1];
              if (tableName) {
                this.logger.log(`创建表: ${tableName}`);
              }
            } catch (error) {
              this.logger.error(`执行建表语句失败: ${statement}`);
              this.logger.error(`错误信息: ${error.message}`);
              throw error;
            }
          }
        }

        // 再创建外键和索引
        for (const statement of createTableStatements) {
          if (statement.trim() && !statement.toUpperCase().includes('CREATE TABLE')) {
            try {
              await this.dataSource.query(statement);
            } catch (error) {
              this.logger.error(`执行其他SQL语句失败: ${statement}`);
              this.logger.error(`错误信息: ${error.message}`);
              // 非建表语句错误不抛出，继续执行
              this.logger.warn('SQL语句执行失败，但将继续执行其他操作');
            }
          }
        }

        // 最后执行触发器
        const triggersSql = await this.readSqlFile(path.join(sqlPath, 'triggers.sql'));
        const triggerStatements = triggersSql
          .split('DELIMITER ;')
          .filter(stmt => stmt.trim());

        for (const statement of triggerStatements) {
          if (statement.trim()) {
            try {
              await this.dataSource.query(statement.replace('DELIMITER //', ''));
            } catch (error) {
              this.logger.error(`执行触发器语句失败: ${statement}`);
              this.logger.error(`错误信息: ${error.message}`);
              // 触发器错误不抛出，继续执行其他操作
              this.logger.warn('触发器创建失败，但将继续执行其他操作');
            }
          }
        }
      }

      this.logger.log('数据库表初始化完成');
    } catch (error) {
      this.logger.error('数据库表初始化失败:', error);
      throw error;
    }
  }

  private getSqlFilePath(): string {
    // 尝试不同的路径
    const possiblePaths = [
      path.join(__dirname, 'sql'),
      path.join(process.cwd(), 'dist', 'database', 'sql'),
      path.join(process.cwd(), 'src', 'database', 'sql')
    ];

    for (const p of possiblePaths) {
      if (fs.existsSync(p)) {
        return p;
      }
    }

    throw new Error('找不到SQL文件目录');
  }

  private async readSqlFile(filePath: string): Promise<string> {
    try {
      this.logger.debug(`尝试读取SQL文件: ${filePath}`);
      return await fs.promises.readFile(filePath, 'utf8');
    } catch (error) {
      this.logger.error(`读取SQL文件失败: ${filePath}`, error);
      throw error;
    }
  }
} 